import { THREE } from '@amcax/web-render';
import { arrow, getPointByVecLen, getScreenNormal } from '../utils';
import { useRenderStore } from '../store';
import { ManagerId } from 'nextcae-base';
import { KeepSizeObject3D } from '.';
import { CSLine } from '.';
export type DimensionAttr = {
  color?: number; // 颜色
  scene?: THREE.Group; // 场景
  points?: THREE.Vector3[]; // 点集
  isExtra?: boolean; // 是否额外
  normal?: THREE.Vector3; // 法向量
  extraLen?: number; // 额外长度
};
/**
 * @description 尺寸标注
 * */
export class Dimension {
  private camera: THREE.OrthographicCamera | THREE.PerspectiveCamera;
  private arrowGroup = new Array<KeepSizeObject3D>(2);
  private scene: THREE.Group;
  private arrowShaft: CSLine;
  private extraLine = new Array<CSLine>(2);
  private isExtra = false;
  private centerPoint: THREE.Vector3; // 中心点
  private points: THREE.Vector3[]; // 点集
  private coordinateInfo = {
    headLength: 1.5,
    headWidth: 0.4,
  };
  constructor(attrs?: DimensionAttr) {
    this.points = attrs?.points;
    this.isExtra = attrs?.isExtra ?? false;
    const { scene, camera } = this.getCameraGroup();
    this.scene = scene;
    this.camera = camera;
    this.arrowGroup[0] = new KeepSizeObject3D(camera); // 坐标系
    this.arrowGroup[1] = new KeepSizeObject3D(camera); // 坐标系
    this.create(attrs);
  }
  create(attrs?: DimensionAttr) {
    if (attrs?.points?.length < 2) {
      return;
    }
    if (this.isExtra) {
      const { p1, p2, p3, p4 } = this.getExraPoints(attrs);
      this.setExtraLine([p1, p2, p3, p4]);
      attrs.points = [p3, p4];
    }
    this.createLine(attrs);
    this.createArrow(attrs);
    this.addTo(attrs?.scene ?? this.scene);
  }
  update(attrs?: DimensionAttr) {
    this.points = attrs?.points ?? this.points;
    const len = attrs?.points?.length;
    if (len < 2) return;
    if (this.isExtra) {
      const { p1, p2, p3, p4 } = this.getExraPoints(attrs);
      attrs.points = [p3, p4];
      this.extraLine[0]?.setVertexs([p1.toArray(), p3.toArray()]);
      this.extraLine[1]?.setVertexs([p2.toArray(), p4.toArray()]);
    }
    // 更新箭头
    this.arrowGroup.forEach((arrow, ind) => {
      const posInd = ind === 0 ? 0 : len - 1;
      const lookInd = ind === 0 ? 1 : len - 2;
      arrow.position.copy(attrs.points[posInd]);
      arrow.lookAt(attrs.points[lookInd]);
    });
    // 更新线段
    this.arrowShaft?.setVertexs(attrs.points.map((point) => point.toArray()));
  }
  createArrow(attrs?: DimensionAttr) {
    const tempArrow = arrow(
      this.coordinateInfo.headLength,
      this.coordinateInfo.headWidth,
      attrs?.color ?? 0x101010,
    );
    tempArrow.rotation.x = -Math.PI / 2; // 旋转90度
    tempArrow.position.setZ(this.coordinateInfo.headLength / 2);
    this.arrowGroup[0].add(tempArrow);
    this.arrowGroup[1].add(tempArrow.clone());
  }
  createLine(attrs?: DimensionAttr) {
    this.arrowShaft = new CSLine({
      vertexes: attrs.points.map((point) => point.toArray()),
      lineWidth: 1,
      color: attrs?.color ?? 0x101010,
    });
  }
  setExtraLine([p1, p2, p3, p4]: THREE.Vector3[], attrs?: DimensionAttr) {
    this.extraLine[0] = new CSLine({
      vertexes: [p1.toArray(), p3.toArray()],
      lineWidth: 1,
      color: attrs?.color ?? 0x101010,
    });
    this.extraLine[1] = new CSLine({
      vertexes: [p2.toArray(), p4.toArray()],
      lineWidth: 1,
      color: attrs?.color ?? 0x101010,
    });
  }
  getExraPoints(attrs?: DimensionAttr) {
    const p1 = attrs.points[0];
    const p2 = attrs.points[attrs.points.length - 1];
    const dir = new THREE.Vector3().subVectors(p2, p1).normalize();
    const axis = attrs?.normal ?? getScreenNormal(this.camera);
    const vec = dir.clone().applyAxisAngle(axis, Math.PI / 2);
    const extraLen = attrs?.extraLen
      ? attrs?.extraLen + this.getLenByZoom(30)
      : this.getLenByZoom(30);
    const p3 = getPointByVecLen(vec, extraLen, p1);
    const p4 = getPointByVecLen(vec, extraLen, p2);
    this.centerPoint = new THREE.Vector3().addVectors(p3, p4).divideScalar(2);
    return { p1, p2, p3, p4 };
  }
  getCameraGroup() {
    const mainRenderer = useRenderStore.getState().mainRenderer;
    return {
      scene: mainRenderer.getEntityManager(ManagerId.Assis).group,
      camera: mainRenderer.cameraManager.camera,
    };
  }
  clear() {
    this.scene?.remove(...this.arrowGroup, ...this.extraLine, this.arrowShaft);
    this.arrowShaft?.destroy();
    this.arrowShaft = null;
    this.arrowGroup.forEach((arrow) => {
      arrow?.clear();
    });
    this.extraLine.forEach((line) => {
      line?.destroy();
    });
  }
  addTo(scene: THREE.Group) {
    if (this.isExtra) {
      scene.add(this.arrowShaft, ...this.arrowGroup, ...this.extraLine);
    } else {
      scene.add(this.arrowShaft, ...this.arrowGroup);
    }
    this.scene = scene;
  }
  public getLenByZoom(num = 40) {
    return num / this.camera.zoom; // 返回 num 除以相机缩放比例的结果
  }
  getCenter() {
    const len = this.points.length;
    if (this.isExtra) {
      return this.centerPoint;
    } else if (len % 2 === 0) {
      const p1 = this.points[len / 2 - 1];
      const p2 = this.points[len / 2];
      return new THREE.Vector3().addVectors(p1, p2).divideScalar(2);
    } else {
      return this.points[Math.floor(len / 2)];
    }
  }
}
